import { arrayUnique, isEqualStrictDeep, map } from '@/utils';
import Queue from '@/utils/Queue';
import request from '@/utils/request';
import voidRender from '@/utils/voidRender';
import React, { useEffect } from 'react';
import { useCall, useSimpleMemo } from '.';
import createSharedHook from './createSharedHook';
import useMap from './useMap';

const mapToValues = (mapObject) => map(mapObject, (v, k) => [k, v]);
const shouldUpdate = ([a], [b]) => !isEqualStrictDeep(mapToValues(a), mapToValues(b));
const initState = [null, () => void 0];
const useSharedState = createSharedHook(useMap, initState, shouldUpdate);
let setSharedState;
const SharedState = () => {
  const [_, setState] = useSharedState();
  setSharedState = setState;
  return null;
};

export const clearDictByCodes = (...codes) => {
  if (codes.length) {
    codes.forEach((code) => {
      setSharedState?.(code, null);
    });
  } else {
    setSharedState?.();
  }
};

voidRender(<SharedState />);

const dictQue = new Queue(async (values) => {
  try {
    const { data } = await request.post('/dictionary/code/findByCodes', null, {
      params: { codes: arrayUnique(values).join(',') },
    });
    return data;
  } catch (error) {
    console.error('dict queue error.', error);
    return null;
  }
});

/**
 * @param {DictionaryItem[]} dictList
 * @return {{ value: String, label: String }[]}
 */
const dictToOptions = (dictList) => dictList.map((v) => ({ value: v.code, label: v.cnName }));

/**
 * @typedef {Object} DictionaryItem   字典对象
 * @property {String} id
 * @property {String} code            字典值
 * @property {String} value
 * @property {String} cnName          字典文本
 */

/**
 * @param {String} code         字典code
 * @param {Boolean} [noCache]   不使用缓存
 * @param {Function} [format]   遍历返回值, 默认会遍历成Option结构
 * @return {ReturnType<format>}
 */
function useDictionary(code, noCache = false, format = dictToOptions) {
  const [shared, setShared] = useSharedState();
  let codeData = useSimpleMemo(code ? shared.get(code) : []);

  const update = useCall(setShared, code);

  useEffect(() => {
    if (codeData == null) return dictQue.enq(code, update);
  }, [codeData]);

  useEffect(() => {
    if (noCache) return dictQue.enq(code, update);
  }, []);

  return useSimpleMemo(format(codeData ?? []));
}

export default useDictionary;
